package org.vehicle.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.UUID;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;


public class FtpUtil {
	private static Logger logger = LogManager.getLogger(FtpUtil.class.getName());
    /**
     * 连接文件服务器
     * @param addr 文件服务器地址
     * @param port 端口
     * @param username 用户名
     * @param password 密码
     * @throws Exception 
     */
    public static FTPClient connect(String addr, int port, String username, String password) {
        logger.info("【连接文件服务器】addr = " + addr + " , port : " + port + " , username = " + username + " , password = "
                    + password);

        FTPClient ftpClient = new FTPClient();
        try {
            // 连接
            ftpClient.connect(addr, port);
            // 登录
            ftpClient.login(username, password);
            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
        } catch (Exception e) {
            logger.error("【连接文件服务器失败】", e);
            throw new RuntimeException("连接文件服务器失败");
        }
        // 判断文件服务器是否可用？？
        if (!FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
            closeConnection(ftpClient);
        }
        return ftpClient;
    }

    /**
     * 连接文件服务器
     * @param addr 文件服务器地址
     * @param port 端口
     * @param username 用户名
     * @param password 密码
     * @param workingDirectory 目标连接工作目录
     * @throws Exception 
     */
    public static FTPClient connect(String addr, int port, String username, String password, String workingDirectory)
                                                                                                                     throws Exception {
        FTPClient ftpClient = connect(addr, port, username, password);
        changeWorkingDirectory(workingDirectory, ftpClient);
        return ftpClient;
    }

    /**
     * 关闭连接，使用完连接之后，一定要关闭连接，否则服务器会抛出 Connection reset by peer的错误
     * @throws IOException
     */
    public static void closeConnection(FTPClient ftpClient) {
        logger.info("【关闭文件服务器连接】");
        if (ftpClient == null) {
            return;
        }
        try {
            ftpClient.disconnect();
        } catch (IOException e) {
            logger.error("【关闭连接失败】", e);
            throw new RuntimeException("关闭连接失败");
        }
    }

    /**
     * 切换工作目录
     * @param directory 目标工作目录
     * @param ftpClient 
     * @throws IOException
     */
    public static void changeWorkingDirectory(String directory, FTPClient ftpClient) {
        logger.info("【切换工作目录】directory : " + directory);
        // 切换到目标工作目录
        try {
            if (!ftpClient.changeWorkingDirectory(directory)) {
                for(String str:directory.split("/")){
                	ftpClient.makeDirectory(str);
                    ftpClient.changeWorkingDirectory(str);
                }
            }
        } catch (IOException e) {
            logger.error("【切换工作目录失败】", e);
            throw new RuntimeException("切换工作目录失败");
        }
    }

    /** 
     * 上传文件/文件夹
     * @param file 上传的文件或文件夹 
     * @return 文件存放的路径以及文件名
     * @throws Exception 
     */
    public static void upload(File file, FTPClient ftpClient) throws Exception {
        if (file == null) {
            logger.warn("【存储的文件为空】");
            throw new RuntimeException("上传文件为空");
        }
        logger.info("【上传文件/文件夹】file ： " + file.getName());

        // 是文件，直接上传
        if (!file.isDirectory()) {
            storeFile(new File(file.getPath()), ftpClient);
            return;
        }

        changeWorkingDirectory(file.getName(), ftpClient);
        // 文件夹，递归上传所有文件
        for (File item : file.listFiles()) {
            if (!item.isDirectory()) {
                storeFile(item, ftpClient);
                continue;
            }
            upload(item, ftpClient);
            ftpClient.changeToParentDirectory();
        }
    }
    /**
     * 返回上级目录
     * @param ftpClient
     */
    public static void changeToParentDirectory(FTPClient ftpClient) {   
	    try {   
	      	ftpClient.changeToParentDirectory();   
	      	System.out.println(ftpClient.printWorkingDirectory());
	    } catch (IOException ioe) {   
	        ioe.printStackTrace();   
	    }   
	}   
    /** 
     * 上传图片
     * @param file 上传的文件或文件夹 
     * @return 文件存放的路径以及文件名
     * @throws Exception 
     */
    public static void upload(String fileName, InputStream is, FTPClient ftpClient) throws Exception {
    	storeFile(fileName,is,ftpClient);
    }

    /**
     * 删除文件
     * @param fileName 要删除的文件地址
     * @return true/false
     * @throws IOException 
     */
    public static boolean delete(String fileName, FTPClient ftpClient) throws IOException {
        logger.info("【删除文件】fileName ： " + fileName);
        return ftpClient.deleteFile(fileName);
    }

    /**
     * 存储文件
     * @param file {@link File}
     * @throws Exception
     */
    public static void storeFile(File file, FTPClient ftpClient) throws Exception {
        if (file == null) {
            logger.warn("【存储的文件为空】");
            throw new RuntimeException("存储的文件为空");
        }
        logger.info("【存储文件】file ： " + file.getName());

        FileInputStream input = new FileInputStream(file);
        ftpClient.storeFile(file.getName(), input);
        input.close();
    }

    /**
     * 存储文件
     * @param InputStream
     * @throws Exception
     */
    public static void storeFile(String fileName,InputStream is, FTPClient ftpClient) throws Exception {
        if (is == null) {
            logger.warn("【存储的文件为空】");
            throw new RuntimeException("存储的文件为空");
        }
        ftpClient.storeFile(fileName, is);
        is.close();
    }
    
    /**
     * 下载文件到指定目录
     * @param ftpFile 文件服务器上的文件地址
     * @param dstFile 输出文件的路径和名称
     * @throws Exception 
     */
    public static void downLoad(String ftpFile, String dstFile, FTPClient ftpClient) throws Exception {
        logger.info("【下载文件到指定目录】ftpFile = " + ftpFile + " , dstFile = " + dstFile);
        if (StringUtils.isBlank(ftpFile)) {
            logger.warn("【参数ftpFile为空】");
            throw new RuntimeException("【参数ftpFile为空】");
        }
        if (StringUtils.isBlank(dstFile)) {
            logger.warn("【参数dstFile为空】");
            throw new RuntimeException("【参数dstFile为空】");
        }
        File file = new File(dstFile);
        FileOutputStream fos = new FileOutputStream(file);
        ftpClient.retrieveFile(ftpFile, fos);
        fos.flush();
        fos.close();
    }

    /**
     * 从文件服务器获取文件流
     * @param ftpFile 文件服务器上的文件地址
     * @return {@link InputStream}
     * @throws IOException
     */
    public static InputStream retrieveFileStream(String ftpFile, FTPClient ftpClient) throws IOException {
        logger.info("【从文件服务器获取文件流】ftpFile ： " + ftpFile);
        if (StringUtils.isBlank(ftpFile)) {
            logger.warn("【参数ftpFile为空】");
            throw new RuntimeException("【参数ftpFile为空】");
        }
        return ftpClient.retrieveFileStream(ftpFile);
    }
    
    
    public static String generateFileName(String originalName) {

        StringBuffer name = new StringBuffer();
        String suffix = FilenameUtils.getExtension(originalName);
            String handlerUUID = getOrderIdByUUId();
            name.append(handlerUUID).append(".").append(suffix);

        return name.toString();

    }
    
    public static String getOrderIdByUUId() {
        int machineId = 1;//最大支持1-9个集群机器部署
        int hashCodeV = UUID.randomUUID().toString().hashCode();
        if (hashCodeV < 0) {//有可能是负数
            hashCodeV = -hashCodeV;
        }
        // 0 代表前面补充0
        // 4 代表长度为4
        // d 代表参数为正数型
        return machineId + String.format("%015d", hashCodeV);
    }
}